#include "utils.h"

#include <iostream>

extern GLuint shader;
const M3DVector3f left_top_corner = {-1.0f, 1.0f, 0.0f};
const M3DVector3f left_down_corner = {-1.0f, -1.0f, 0.0f};
const M3DVector3f right_top_corner = {1.0f, 1.0f, 0.0f};
const M3DVector3f right_down_corner = {1.0f, -1.0f, 0.0f};
const M3DVector3f top = {0.0f, 0.0f, 2.0f};
const M3DVector3f base_normal = {0.0, 0.0f, -1.0f};
const M3DVector3f floor_normal = {0.0, 0.0f, 1.0f};

void TriangleFace(const M3DVector3f a, const M3DVector3f b, const M3DVector3f c) {
   
   M3DVector3f normal, bMa, cMa;
   m3dSubtractVectors3(bMa, b, a);
   m3dSubtractVectors3(cMa, c, a);
   m3dCrossProduct3(normal, bMa, cMa);
   m3dNormalizeVector3(normal);
   glVertexAttrib3fv(GLT_ATTRIBUTE_NORMAL, normal);
   glVertex3fv(a);
   glVertex3fv(b);
   glVertex3fv(c);
}

void SetUpFrame(GLFrame &frame, const M3DVector3f origin,
				const M3DVector3f forward,	const M3DVector3f up) 
{
	M3DVector3f side, oUp;
	frame.SetOrigin(origin);
	frame.SetForwardVector(forward);

	m3dCrossProduct3(side, forward, up);
	m3dCrossProduct3(oUp, side, forward);
	frame.SetUpVector(oUp);
	frame.Normalize();
}

void LookAt(GLFrame &frame, const M3DVector3f eye,
			const M3DVector3f at,
			const M3DVector3f up) 
{
    M3DVector3f forward;
    m3dSubtractVectors3(forward, at, eye);
    SetUpFrame(frame, eye, forward, up);
}

void DrawGrid(GLfloat xMin, GLfloat yMin, GLfloat xMax, GLfloat yMax, GLint n, GLfloat z) 
{
    GLfloat deltaX = (xMax - xMin) / n;
    GLfloat deltaY = (yMax - yMin) / n;
    glBegin(GL_LINES);
    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0f, 0.0f, 0.0f);
    
	for (int i = 0; i <= n; i++) {
        glVertex3f(deltaX * i + xMin, yMin, z);
        glVertex3f(deltaX * i + xMin, yMax, z);
        glVertex3f(xMin, deltaY * i + yMin, z);
        glVertex3f(xMax, deltaY * i + yMin, z);
    }

    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 1.0f, 0.0f, 0.0f);
    glVertex3f(xMax, 0, 0.1);
    glVertex3f(0, 0, 0.1);
    glVertexAttrib3f(GLT_ATTRIBUTE_COLOR, 0.0f, 0.0f, 1.0f);
    glVertex3f(0, yMax, 0.1);
    glVertex3f(0, 0, 0.1);
    glEnd();
}

void DrawPyramide(void)
{
	/* base, grey color, turned downwards */
	glFrontFace(GL_CW);
	glBegin(GL_QUADS); 
	glVertexAttrib3fv(GLT_ATTRIBUTE_NORMAL, base_normal);
	glVertex3fv(left_top_corner);
    glVertex3fv(right_top_corner);
    glVertex3fv(right_down_corner);
	glVertex3fv(left_down_corner);
	glEnd();

	glFrontFace(GL_CCW);
	/* green triangle */
	glBegin(GL_TRIANGLES);
	TriangleFace(left_down_corner, right_down_corner, top); 
    glEnd();

	/* blue triangle */
	glBegin(GL_TRIANGLES);
	TriangleFace(left_top_corner, left_down_corner, top);
    glEnd();

	/* yellow triangle */
    glBegin(GL_TRIANGLES);
	TriangleFace(left_top_corner, top, right_top_corner);
    glEnd();

	/* red triangle */
	glBegin(GL_TRIANGLES);
	TriangleFace(right_down_corner, right_top_corner, top);
    glEnd();
}

void DrawFloor(GLfloat xMin, GLfloat yMin, GLfloat xMax, GLfloat yMax)
{
	glBegin(GL_QUADS);
	glVertexAttrib3fv(GLT_ATTRIBUTE_NORMAL, floor_normal);
	glVertexAttrib2f(GLT_ATTRIBUTE_TEXTURE0, 0, 0);
	glVertex3f(xMin, yMin, 0.0f);
	glVertexAttrib2f(GLT_ATTRIBUTE_TEXTURE0, 0, 1);
	glVertex3f(xMax, yMin, 0.0f);
	glVertexAttrib2f(GLT_ATTRIBUTE_TEXTURE0, 1, 1);
	glVertex3f(xMax, yMax, 0.0f);
	glVertexAttrib2f(GLT_ATTRIBUTE_TEXTURE0, 1, 0);
	glVertex3f(xMin, yMax, 0.0f);
	glEnd();
}

void GetUniformLocationExt(GLint *var, const char *name)
{
	*var = glGetUniformLocation(shader, name);
	if (*var == (-1))
	{
		std::cerr << "uniform " << name << " could not be found " << glGetError() <<std::endl;
	}
}

int ReadVertices(std::vector<float> &vector)
{
	char line[120];
	int vertices_nr = 0;
	FILE *fvertices = fopen("geode_vertices.dat","r");
	
	if (fvertices == NULL) 
	{
		std::cerr << "cannot open vertices file for reading" << std::endl;
		exit(-1);
	}
	
	while (fgets(line,120,fvertices) != NULL) 
	{
		float x,y,z;
		double norm;
		sscanf(line, "%f %f %f",&x,&y,&z);
  
		norm=x*x+y*y+z*z;
		norm=sqrt(norm);
		vertices_nr++;
		vector.push_back(x);
		vector.push_back(y);
		vector.push_back(z);
		vector.push_back(1.0f);
		vector.push_back(x/norm);
		vector.push_back(y/norm);
		vector.push_back(z/norm);
	}

	std::cerr << "nv = " << vertices_nr << " vector_size " << vector.size() << std::endl;
	return vertices_nr;
}

int ReadWalls(std::vector<GLint> &vector)
{
	char line[120];
	int faces_nr = 0;
	FILE *ffaces = fopen("geode_faces.dat","r");
	
	if (ffaces == NULL) 
	{
		std::cerr << "cannot open faces file for reading" << std::endl;
		exit(-1);
	}

	while (fgets (line, 120, ffaces) != NULL) 
	{
		GLuint  i,j,k;
   
		if (3 != sscanf(line,"%u %u %u",&i,&j,&k))
		{
			std::cerr << "error reading faces" << std::endl; 
			exit(-1);
		}
		faces_nr++;
		vector.push_back(i-1);
		vector.push_back(j-1);
		vector.push_back(k-1);
	}

	std::cerr << "nf = " << faces_nr << std::endl;
	return faces_nr;
}